import grails.util.GrailsNameUtils
import org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator
import org.codehaus.groovy.grails.validation.ConstrainedProperty
import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass

includeTargets << grailsScript("Init")
includeTargets << grailsScript("_GrailsBootstrap")
includeTargets << grailsScript("_GrailsCreateArtifacts")

generateForName = null

target(main: "Generates i18n messages for domain classes") {
    depends(checkVersion, parseArguments, packageApp)
    promptForName(type: "Domain Class")
    generateI18nMessages()
}

setDefaultTarget(main)

target(generateI18nMessages: "The implementation target") {
    try {
        def name = argsMap["params"][0]
        if (!name || name == "*") {
            uberGenerate()
        }
        else {
            generateForName = name
            generateForOne()
        }
    }
    catch (Exception e) {
        logError("Error running generate-i18n-messages", e)
        exit(1)
    }
}

target(generateForOne: "Generates i18n messages for only one domain class") {
    depends(loadApp)

    def name = generateForName
    name = name.indexOf('.') > -1 ? name : GrailsNameUtils.getClassNameRepresentation(name)
    def domainClass = grailsApp.getDomainClass(name)

    if (!domainClass) {
        println "Domain class not found in grails-app/domain, trying hibernate mapped classes..."
        bootstrap()
        domainClass = grailsApp.getDomainClass(name)
    }

    if (domainClass) {
        generateForDomainClass(domainClass)
        event("StatusFinal", ["Finished generation for domain class ${domainClass.fullName}. Copy messages to appropriate resource bundle(s)"])
    }
    else {
        event("StatusFinal", ["No domain class found for name ${name}. Please try again and enter a valid domain class name"])
    }
}

target(uberGenerate: "Generates i18n messages for all domain classes") {
    depends(loadApp)

    def domainClasses = grailsApp.domainClasses

    if (!domainClasses) {
        println "No domain classes found in grails-app/domain, trying hibernate mapped classes..."
        bootstrap()
        domainClasses = grailsApp.domainClasses
    }

   if (domainClasses) {
        domainClasses.each { domainClass ->
            generateForDomainClass(domainClass)
        }
        event("StatusFinal", ["Finished generation for domain classes. Copy messages to appropriate resource bundle(s)"])
    }
    else {
        event("StatusFinal", ["No domain classes found"])
    }
}

def generateForDomainClass(DefaultGrailsDomainClass domainClass) {
//  println   domainClass.
//  println domainClass.class
  def propertiesFiles = ['default':new File("${basedir}/grails-app/i18n/${domainClass.propertyName}.properties")]
  propertiesFiles['default'].write('')
//TODO configure Languages global and in domain classes

    props = domainClass.getConstrainedProperties() //properties.findAll { it.name != 'version' }

//    Collections.sort(props, new DomainClassPropertyComparator(domainClass))
    propertiesFiles['default'] << "${domainClass.propertyName}.menu=${domainClass.shortName}\n"
    propertiesFiles['default'] << "${domainClass.propertyName}.label=${domainClass.shortName}\n"
//TODO
//    domainClass.i18n?.each{lang, kv->
//      kv.each{key, value->
//        propertiesFiles[lang] << "$key=$value\n"
//      }
//    }

    props.each { constrainedProperty ->
      def p = domainClass.getPropertyByName(constrainedProperty.key)
      println "Property: ${p.name}"
      if(constrainedProperty.value?.attributes?.i18n?.location == 'global' || p.name=='compositeId' || p.name=='id')return
        propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.label=${p.naturalName}\n"
        propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.hint=${p.naturalName}\n"

        // print messages for inList constaint values
        cp = domainClass.constrainedProperties[p.name]
        if (cp?.inList) {
            cp.inList.each { v ->
                propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${v}=${v}\n"
            }
        }

        // print error messages for constraints
        cp?.appliedConstraints?.each { c ->
            switch (c.name) {
                case ConstrainedProperty.BLANK_CONSTRAINT:
                    if (!c.parameter)
                        propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] cannot be blank\n"
                    break
                case ConstrainedProperty.CREDIT_CARD_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not a valid credit card number\n"
                    break
                case ConstrainedProperty.EMAIL_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not a valid e-mail address\n"
                    break
                case ConstrainedProperty.IN_LIST_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not contained within the list [{3}]\n"
                    break
                case ConstrainedProperty.MATCHES_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not match the required pattern [{3}]\n"
                    break
                case ConstrainedProperty.MAX_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] exceeds maximum value [{3}}\n"
                    break
                case ConstrainedProperty.MAX_SIZE_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] exceeds the maximum size of [{3}}\n"
                    break
                case ConstrainedProperty.MIN_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is less than minimum value [{3}}\n"
                    break
                case ConstrainedProperty.MIN_SIZE_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is less than the minimum size of [{3}}\n"
                    break
                case ConstrainedProperty.NOT_EQUAL_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] cannot equal [{3}}\n"
                    break
                case ConstrainedProperty.NULLABLE_CONSTRAINT:
                    if (!c.nullable)
                        propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] cannot be null\n"
                    break
                case ConstrainedProperty.RANGE_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not fall within the valid range from [{3}] to [{4}}\n"
                    break
                case ConstrainedProperty.SIZE_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}}\n"
                    break
                //case ConstrainedProperty.UNIQUE_CONSTRAINT: // unique constraint reference not available
                //    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] must be unique"
                //    break
                case ConstrainedProperty.URL_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not a valid URL\n"
                    break
                case ConstrainedProperty.VALIDATOR_CONSTRAINT:
                    propertiesFiles['default'] << "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not pass custom validation\n"
                    break
            }
        }
    }
    propertiesFiles['default'] << ""
}
